
import java.util.List;

public class SyntaxParser {

    private List<Token> tokenList;
    private int index;

    public void parser(List<Token> tokenList) {
        this.tokenList = tokenList;
        this.index = 0;
        program();
    }

    /**
     * <程序> => <声明><程序>|ε
     */
    private void program() {
        if (isNull()) return;
        index--;
        statement();
        if (isNull()) return;
        // 再读一个
        index++;
        program();
    }

    /**
     * <声明> => <变量声明>|<函数声明>
     */
    private void statement() {
        // <变量类型><标识符>
        if (!isVariableType()) exception();
        if (!isIdentifier()) exception();
        // 判断下一个token
        index++;
        switch (tokenList.get(index).getWord()) {
            case ";":
                return;
            case "=":
                // <算术表达式>
                arithmeticExpression();
                index++;
                if (!tokenList.get(index).getWord().equals(";")) exception();
                return;
            case "(":
                // <参数列表>){<内部代码块>}
                // 空参判断
                if (!isVariableType()) {
                    index--;
                } else {
                    index--;
                    paramList();
                }
                index++;
                if (!tokenList.get(index).getWord().equals(")")) exception();
                index++;
                if (!tokenList.get(index).getWord().equals("{")) exception();
                // 代码块为空
                index++;
                if (tokenList.get(index).getWord().equals("}")) {
                    return;
                } else {
                    index--;
                    innerCodeBlock();
                }
                index++;
                if (!tokenList.get(index).getWord().equals("}")) exception();
        }
    }

    /**
     * 算术表达式
     */
    private void arithmeticExpression() {
        index++;
        switch (tokenList.get(index).getTokenType()) {
            case Identifier:
            case Float_Literal:
            case Int_Literal:
            case Char_Literal:
                arithmeticExpression2();
                return;
        }
        exception();
    }

    private void arithmeticExpression2() {
        index++;
        switch (tokenList.get(index).getWord()) {
            case "+":
            case "-":
            case "*":
            case "/":
                arithmeticExpression();
                return;
        }
        index--;
    }

    /**
     * <参数列表> => ε|<变量类型><标识符>|<变量类型><标识符>,<参数列表>
     */
    private void paramList() {
        if (!isVariableType()) exception();
        if (!isIdentifier()) exception();
        index++;
        if (tokenList.get(index).getWord().equals(",")) {
            paramList();
            return;
        }
        index--;
    }

    private void paramList2() {
        index++;
        if (tokenList.get(index).getWord().equals(",")) paramList();
        else index--;
    }


    /**
     * <内部代码块> => ε|<变量声明>|<ifelse判断>|<while循环>|<返回语句>
     */
    private void innerCodeBlock() {
        // 判断是不是}
        index++;
        if (tokenList.get(index).getWord().equals("}")) {
            index--;
            return;
        } else index--;

        if (isVariableType()) {
            if (!isIdentifier()) exception();
            index++;
            if (tokenList.get(index).getWord().equals(";")) {
                return;
            } else if (tokenList.get(index).getWord().equals("=")) {
                arithmeticExpression();
                index++;
                if (!tokenList.get(index).getWord().equals(";")) exception();
                innerCodeBlock();
                return;
            }
        }

        switch (tokenList.get(index).getTokenType()) {
            case If:
                // <ifelse判断>
                ifElseJudgment();
                break;
            case While:
                whileLoop();
                break;
            case Return:
                returnStatement();
                break;
        }
    }

    /**
     * <返回语句> => return<赋值表达式>;
     */
    private void returnStatement() {
        index++;
        if (tokenList.get(index).getWord().equals(";")) return;
        else {
            index--;
        }
        if (isIdentifier()) {
            index++;
            switch (tokenList.get(index).getWord()){
                case "=":
                case ">":
                case "<":
                    break;
                default:
                    index-=2;
            }
            arithmeticExpression();
        } else {
            index--;
        }
        index++;
        if (!tokenList.get(index).getWord().equals(";")) exception();
        innerCodeBlock();
    }

    /**
     * <while循环> => while(<赋值表达式>){<内部代码块>}
     */
    private void whileLoop() {
        index++;
        if (!tokenList.get(index).getWord().equals("(")) exception();
        if (isIdentifier()) {
            index++;
            switch (tokenList.get(index).getWord()){
                case "=":
                case ">":
                case "<":
                    break;
                default:
                    index-=2;
            }
            arithmeticExpression();
        } else {
            index--;
        }


        index++;
        if (!tokenList.get(index).getWord().equals(")")) exception();
        index++;
        if (!tokenList.get(index).getWord().equals("{")) exception();

        innerCodeBlock();
        index++;
        if (!tokenList.get(index).getWord().equals("}")) exception();
        innerCodeBlock();
    }

    /**
     * <ifelse判断> => if(<赋值表达式>){<内部代码块>}else{<内部代码块>}
     */
    private void ifElseJudgment() {
        index++;
        if (!tokenList.get(index).getWord().equals("(")) exception();
        if (isIdentifier()) {
            index++;
            switch (tokenList.get(index).getWord()){
                case "=":
                case ">":
                case "<":
                    break;
                default:
                    index-=2;
            }
            arithmeticExpression();
        } else {
            index--;
        }


        index++;
        if (!tokenList.get(index).getWord().equals(")")) exception();
        index++;
        if (!tokenList.get(index).getWord().equals("{")) exception();

        innerCodeBlock();
        index++;
        if (!tokenList.get(index).getWord().equals("}")) exception();

        // else{<内部代码块>}
        index++;
        if (tokenList.get(index).getTokenType() == TokenType.Else) {
            index++;
            if (!tokenList.get(index).getWord().equals("{")) exception();
            innerCodeBlock();
            index++;
            if (!tokenList.get(index).getWord().equals("}")) exception();
        } else {
            index--;
        }
        innerCodeBlock();
    }


    /**
     * 判断是否为 变量类型
     *
     * @return true or false
     */
    private boolean isVariableType() {
        index++;
        switch (tokenList.get(index).getTokenType()) {
            case Int:
            case Float:
            case Char:
            case Void:
                return true;
        }
        return false;
    }

    /**
     * 判断是不是标识符
     *
     * @return true or false
     */
    private boolean isIdentifier() {
        index++;
        return tokenList.get(index).getTokenType() == TokenType.Identifier;
    }

    /**
     * 判断是不是字面量
     */
    private boolean isLiteral(){
        index++;
        switch (tokenList.get(index).getTokenType()){
            case Int_Literal:
            case Float_Literal:
            case Char_Literal:
                return true;
        }
        return false;
    }


    /**
     * 判断tokenList中是否读到了最后
     *
     * @return
     */
    private Boolean isNull() {
        return index >= tokenList.size();
    }

    /**
     * 抛出异常
     */
    private void exception() {
        String errMsg = String.format("Syntax error,unable to parse '%s',in line %d",
                tokenList.get(index).getWord(),tokenList.get(index).getRow());
        try {
            throw new Exception(errMsg);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(-1);
    }


    public List<Token> getTokenList() {
        return tokenList;
    }

    public void setTokenList(List<Token> tokenList) {
        this.tokenList = tokenList;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}
